//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_DATETIME_CDATETIME_H_
#define _BUOLA_DATETIME_CDATETIME_H_

#include <buola/datetime/cdate.h>
#include <buola/datetime/ctimeofday.h>
#include <buola/utility/operators.h>
#include <buola/io.h>

namespace buola {

///\addtogroup datetime
///@{

////////////////////////////////////////////////////////////////////////////

/// date/time object

/// This class represents a time point as a date and a time of day
///
/// It also includes the time zone for the representation
///
////////////////////////////////////////////////////////////////////////////

class CDateTime : public ops::UComparison<CDateTime>
{
public:
    ///default constructor

    ///sets a null date and a zero time of day
    CDateTime()
    {}

    ///initializes the date and time from a calendar time

    ///\param pTime a point in calendar time
    ///\param pTZ the time zone to use for the conversion
    explicit CDateTime(const CCalendarTime &pTime,const CTimeZone &pTZ=CTimeZone());

    ///initializes the date/time object from a date

    ///Time of day is set to 00:00:00
    explicit CDateTime(const CDate &pDate,const CTimeZone &pTZ=CTimeZone())
        :   mDate(pDate)
        ,   mTime(0,0)
        ,   mTZ(pTZ)
    {}

    ///initializes the date/time object from a date and a time of day
    CDateTime(const CDate &pDate,const CTimeOfDay &pTime,const CTimeZone &pTZ=CTimeZone())
        :   mDate(pDate)
        ,   mTime(pTime)
        ,   mTZ(pTZ)
    {}

    ///copy constructor
    CDateTime(const CDateTime &pDT)
        :   mDate(pDT.mDate),
            mTime(pDT.mTime),
            mTZ(pDT.mTZ)
    {}

    ///destructor
    ~CDateTime()
    {
    }

    ///returns true if it represents a null value
    bool IsNull()
    {
        return mDate.IsNull();
    }

    ///returns true if both the date and the time of day are well-formed
    bool IsWellFormed()
    {
        return mDate.IsWellFormed()&&mTime.IsWellFormed();
    }

    ///returns the date/time as text, according to current locale
    std::wstring GetText() const;
    ///returns the date/time as text, according to current locale, including the time zone
    std::wstring GetTextWithTimeZone() const;
    ///returns an ISO string representing the date and time
    std::wstring GetISODateTime() const;

    ///returns the date part of the object
    const CDate &Date() const
    {
        return mDate;
    }

    ///returns the time of day part of the object
    const CTimeOfDay &Time() const
    {
        return mTime;
    }

    ///returns the date part of the object (non-const version)
    CDate &Date()
    {
        return mDate;
    }

    ///returns the time of day part of the object (non-const version)
    CTimeOfDay &Time()
    {
        return mTime;
    }

    ///returns the time zone
    const CTimeZone &TimeZone() const
    {
        return mTZ;
    }

    ///normalizes the date/time object so that it is well-formed

    ///This function would, for example, convert the 40th of March to the 9th of April, or 27:00:00 on January 1st
    ///to 03:00:00 on January 2nd.
    void Normalize();

    ///equality operator
    bool operator==(const CDateTime &pRH) const
    {
        return mDate==pRH.mDate&&mTime==pRH.mTime;
    }

    ///comparison less-than operator
    bool operator<(const CDateTime &pRH) const
    {
        return (mDate<pRH.mDate||(mDate==pRH.mDate&&mTime<pRH.mTime));
    }

    ///returns the calendar time corresponding to this date/time object

    ///The stored time zone is used for the conversion
    CCalendarTime GetCalendarTime() const;

private:
    CDate mDate;
    CTimeOfDay mTime;
    CTimeZone mTZ;
};

///enables printing of calendar time
inline io::CTextWriter &operator<<(io::CTextWriter &pWriter,const CCalendarTime &pTime)
{
    pWriter << CDateTime(pTime).GetText();
    return pWriter;
}

///@}

/*namespace buola*/ }

#endif
